#!/usr/bin/env node
/**
 * 项目脚手架脚本
 * 功能：
 * 1. 根据用户输入或命令行参数创建新项目目录
 * 2. 将 template/ 下的所有文件拷贝到目标目录
 * 3. 自动改写 package.json、index.html、src/config.js 中的项目名
 * 4. 输出后续命令提示
 *
 * 用法：
 *   node create-app.mjs [projectName]
 *   如果省略 projectName，会交互式询问
 */

import minimist from 'minimist';
import chalk from 'chalk';
import prompts from 'prompts';
import path from 'node:path';
import fs from 'node:fs';
import { fileURLToPath } from 'node:url';

/* -------------------- 命令行解析 -------------------- */
const argv = minimist(process.argv.slice(2), { string: ['_'] });

/** 去掉末尾多余的 "/" */
function formatTargetDir(targetDir: string | undefined): string | undefined {
  return targetDir?.trim().replace(/\/+$/g, '');
}

/** 默认目录名 */
const DEFAULT_DIR = 'niuma-admin';

/* -------------------- 主流程 -------------------- */
async function init(): Promise<void> {
  /* 获取目录名（优先用命令行参数，否则交互式） */
  const argTargetDir = formatTargetDir(argv._[0]);
  let targetDir = argTargetDir || DEFAULT_DIR;

  /* 交互式提示（仅当命令行未传目录名时） */
  if (!argTargetDir) {
    try {
      const response = await prompts({
        type: 'text',
        name: 'projectName',
        message: chalk.reset('Project name:'),
        initial: DEFAULT_DIR,
        onState: (state) => {
          targetDir = formatTargetDir(state.value) || DEFAULT_DIR;
        },
      });

      /* 用户取消 Ctrl + C */
      if (!response.projectName) {
        throw new Error(chalk.red('✖') + ' Operation cancelled');
      }
    } catch (cancelled: any) {
      console.log(cancelled.message);
      return;
    }
  }

  /* 计算绝对路径 */
  const root = path.join(process.cwd(), targetDir);

  /* 模板目录定位（相对于本文件） */
  const templateDir = path.resolve(
    fileURLToPath(import.meta.url),
    '../..',
    'template'
  );

  /* 需要改名的文件映射 */
  const renameFiles: Record<string, string> = {
    _gitignore: '.gitignore',
  };

  /** 将单个文件写入目标目录（支持重命名） */
  function write(srcFile: string, content?: string): void {
    const destFile = path.join(root, renameFiles[srcFile] ?? srcFile);
    if (content) {
      fs.writeFileSync(destFile, content);
    } else {
      copy(path.join(templateDir, srcFile), destFile);
    }
  }

  /** 递归拷贝目录 */
  function copyDir(srcDir: string, destDir: string): void {
    fs.mkdirSync(destDir, { recursive: true });
    for (const file of fs.readdirSync(srcDir)) {
      copy(path.resolve(srcDir, file), path.resolve(destDir, file));
    }
  }

  /** 拷贝文件或目录（递归） */
  function copy(src: string, dest: string): void {
    const stat = fs.statSync(src);
    if (stat.isDirectory()) {
      copyDir(src, dest);
    } else {
      fs.copyFileSync(src, dest);
    }
  }

  /* -------------------- 正式写入 -------------------- */
  console.log(`\nScaffolding project in ${chalk.cyan(root)}...\n`);

  /* 创建根目录 */
  if (!fs.existsSync(root)) {
    fs.mkdirSync(root, { recursive: true });
  }

  /* 拷贝模板 */
  for (const file of fs.readdirSync(templateDir)) {
    write(file);
  }

  /* 改写关键文件中的项目名 */
  await replaceProjectName(root, targetDir);

  /* -------------------- 输出后续命令 -------------------- */
  const cdProjectName = path.relative(process.cwd(), root);
  console.log(`\nDone. Now run:\n`);
  if (root !== process.cwd()) {
    console.log(
      `  cd ${
        cdProjectName.includes(' ') ? `"${cdProjectName}"` : cdProjectName
      }`
    );
  }
  console.log(`  npm install`);
  console.log(`  npm run dev\n`);
}

/* -------------------- 辅助：替换项目名 -------------------- */
async function replaceProjectName(root: string, name: string): Promise<void> {
  const pkgPath = path.join(root, 'package.json');
  if (fs.existsSync(pkgPath)) {
    const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
    pkg.name = name;
    fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2));
  }

  const htmlPath = path.join(root, 'index.html');
  if (fs.existsSync(htmlPath)) {
    let html = fs.readFileSync(htmlPath, 'utf-8');
    html = html.replace(/<title>.*?<\/title>/i, `<title>${name}</title>`);
    fs.writeFileSync(htmlPath, html);
  }

  const configPath = path.join(root, 'src', 'config.js');
  if (fs.existsSync(configPath)) {
    let content = fs.readFileSync(configPath, 'utf-8');
    content = content.replace(
      /projectName\s*:\s*['"][^'"]+['"]/,
      `projectName: '${name}'`
    );
    fs.writeFileSync(configPath, content);
  }
}

/* -------------------- 启动 -------------------- */
init().catch((e) => {
  console.error(e);
  process.exit(1);
});
